#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static int pid = -1;
static int sd = -1;
static struct sockaddr serv_addr;
static socklen_t serv_alen;
static char ticket_buf[128];
static int have_ticket = 0;
static int slot = -1;

#define BUFSIZE	256
#define MSGLEN 256
#define SERVER_PORTNUM 2020
#define HOSTLEN 256
#define oops(p) {perror(p); exit(1);}

int make_dgram_client_socket();
int make_internet_address(char *, int, struct sockaddr_in *);
int get_internet_address(char *, int, int *, struct sockaddr_in *);
char * do_transaction(char * msg);
void syserr(char * msg1);
void narrate(char * msg1, char * msg2);
void shut_down();
int get_ticket(char * PZ);
int release_ticket(char * PZ);
char * do_transaction(char * msg);


void setup(){
    char hostname[BUFSIZE];
    pid = getpid();
    sd = make_dgram_client_socket();
    if (sd == -1)
        oops("Cannot create socket");
    gethostname(hostname, HOSTLEN);
    make_internet_address(hostname, SERVER_PORTNUM, (struct sockaddr_in*)&serv_addr);
    serv_alen = sizeof(serv_addr);
}

void shut_down(){
    close(sd);
}

int get_ticket(char * PZ){
    char * response;
    char buf[MSGLEN];
    if (have_ticket)
        return 0;
    sprintf(buf, "HELO %d %s", pid, PZ);
    if ((response = do_transaction(buf)) == NULL)
        return -1;
    if (strncmp(response, "TICK", 4) == 0){
        strcpy(ticket_buf, response+5);
        have_ticket = 1;
        int temp;
        sscanf(ticket_buf, "%d. %d", &temp, &slot); 
        narrate("got ticket", ticket_buf);
        return 0;
    }
    if (strncmp(response, "FAIL", 4) == 0)
        narrate("Could not get ticket", response);
    else
        narrate("Unknown message:", response);
    return -1;
}
int test_ticket(char * PZ){
    char * response;
    char buf[MSGLEN];
    sprintf(buf, "VALD %d. %d %s", pid, slot, PZ);
    if ((response = do_transaction(buf)) == NULL)
        return -1;
    if (strncmp(response, "GOOD", 4) == 0){
        have_ticket = 1;
        narrate("Test valid:", response+5);
        return 0;
    }
    if (strncmp(response, "FAIL", 4) == 0)
        narrate("Ticket is invalid:", response);
    else
        narrate("Unknown message:", response);
    have_ticket = 0;
    return -1;
}
int release_ticket(char * PZ){
    char buf[MSGLEN];
    char * response;
    if (!have_ticket)
        return 0;
    sprintf(buf, "GBYE %s %s", ticket_buf, PZ);
    if ((response = do_transaction(buf)) == NULL)
        return -1;
    if (strncmp(response, "THNX", 4) == 0){
        narrate("released ticket OK", "");
        return 0;
    }
    if (strncmp(response, "FAIL", 4) == 0)
        narrate("release failed", response+5);
    else
        narrate("Unknown message:", response);
    return -1;
}
char * do_transaction(char * msg){
    static char buf[MSGLEN];
    struct sockaddr retaddr;
    socklen_t addrlen = sizeof(retaddr);
    int res;
    res = sendto(sd, msg, strlen(msg), 0, &serv_addr, serv_alen);
    if (res == -1){
        syserr("sendto");
        return NULL;
    }
    res = recvfrom(sd, buf, MSGLEN, 0, &retaddr, &addrlen);
    if (res == -1){
        syserr("recvfrom");
        return NULL;
    }
    return buf;
 }
 void narrate(char * msg1, char * msg2){
     fprintf(stderr, "CLIENT[%d]:%s %s\n", pid, msg1, msg2);
 }
 void syserr(char * msg1){
     char buf[MSGLEN];
     sprintf(buf, "CLIENT[%d], %s", pid, msg1);
     perror(buf);
 }
